# -*-coding:utf-8-*-


class Meta(type):
    """
    (1)
    实现动态修改类属性可以在init或new方法中。在new方法中是修改classdict的键值，但要在super().new之前；
    在init方法中只能直接对cls做修改才有效，修改classdict的键值是无效的。
    (2)
    以Meta为元类的类Base拥有装饰器decorator时，执行顺序：
    Meta.__new__
    Meta.__init__
    decorator.__init__
    decorator.__call__
    Meta.__call__
    Base.__new__
    Base.__init__
    """
    # cls代指以该类为元类的类Base, __init__方法初始化Base类对象
    def __init__(cls, classname, supers, classdict):
        cls.x = 1  # 动态修改类属性. cls.x=1有效, classdict['x']=1无效
        print("MetaClass.__init__: ", cls, classname, supers, classdict)
        super().__init__(classname, supers, classdict)

    # mcs代指元类自身, __new__方法返回Base类对象
    def __new__(mcs, classname, supers, classdict):
        classdict['y'] = 2  # 动态修改类属性
        print("MetaClass.__new__: ", mcs, classname, supers, classdict)
        return super().__new__(mcs, classname, supers, classdict)

    # cls代指以该类为元类的类Base, __call__方法在Base类对象进行实例化时触发
    def __call__(cls, *args, **kwargs):
        print("MetaClass.__call__: ", cls, args, kwargs)
        obj = cls.__new__(cls, *args, **kwargs)
        cls.__init__(obj, *args, **kwargs)
        return obj
        # return super().__call__(*args, **kwargs)

# 定义类Base时，将调用元类的__new__方法和__init__方法
class Base(object, metaclass=Meta):
    def __init__(self, name):
        self.name = name

if __name__ == '__main__':
    # Base 实例化时会调用元类的__call__方法。
    b = Base("abc")
    print(b.x, b.y)
